﻿using Foxit.PDF;
using Foxit.PDF.Imaging;
using Foxit.PDF.PageElements;
using Sustainalytics.ClientDW.Entities;
using Sustainalytics.Reporting.Framework;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using Sustainalytics.Entities;
using Sustainalytics.ESG.Entities;

namespace Sustainalytics.ReportGenerator.BL
{
    public class StandardIndicatorsSection : IPdfDocumentGenerator
    {
        private CompanyReportDataOffline _dataSource;
        private PdfReport _report;
        private List<OutlinePosition> _outlinePositions;
        private List<PageElementPosition> _pageElementPositions;

        # region Static Images

        private static byte[] _trendArrowDown;
        private static byte[] _trendArrowUp;
        private static byte[] _trendArrowRight;
        public byte[] TrendArrowDown { get { return _trendArrowDown; } }
        public byte[] TrendArrowUp { get { return _trendArrowUp; } }
        public byte[] TrendArrowRight { get { return _trendArrowRight; } }

        private static byte[] _outlookArrowDown;
        private static byte[] _outlookArrowUp;
        private static byte[] _outlookArrowRight;
        public byte[] OutlookArrowDown { get { return _outlookArrowDown; } }
        public byte[] OutlookArrowUp { get { return _outlookArrowUp; } }
        public byte[] OutlookArrowRight { get { return _outlookArrowRight; } }

        private static byte[] _tickboxChecked;
        private static byte[] _tickboxUnchecked;
        public byte[] TickboxChecked { get { return _tickboxChecked; } }
        public byte[] TickboxUnchecked { get { return _tickboxUnchecked; } }

        static void LoadStaticImages()
        {
            if (_trendArrowDown == null)
                _trendArrowDown = ImagesGenerator.GetJpgImage(@"Images\trend_arrow_down.jpg");

            if (_trendArrowUp == null)
                _trendArrowUp = ImagesGenerator.GetJpgImage(@"Images\trend_arrow_up.jpg");

            if (_trendArrowRight == null)
                _trendArrowRight = ImagesGenerator.GetJpgImage(@"Images\trend_arrow_right.jpg");


            if (_outlookArrowDown == null)
                _outlookArrowDown = ImagesGenerator.GetJpgImage(@"Images\outlook_arrow_down.jpg");

            if (_outlookArrowUp == null)
                _outlookArrowUp = ImagesGenerator.GetJpgImage(@"Images\outlook_arrow_up.jpg");

            if (_outlookArrowRight == null)
                _outlookArrowRight = ImagesGenerator.GetJpgImage(@"Images\outlook_arrow_right.jpg");

            
            if (_tickboxChecked == null)
                _tickboxChecked = ImagesGenerator.GetJpgImage(@"Images\TickboxChecked.jpg");

            if (_tickboxUnchecked == null)
                _tickboxUnchecked = ImagesGenerator.GetJpgImage(@"Images\TickboxUnchecked.jpg");
        }

        #endregion

        public bool ShowOutlines { get; set; }

        static StandardIndicatorsSection()
        {
            LoadStaticImages();
        }

        public GenerationResult GeneratePdfDocument(CompanyReportDataOffline crdo)
        {
            var result = new GenerationResult
            {
                ReportType = crdo.ReportType,
                ReportGeneratorType = ReportGeneratorType.SourcesSection,
                OutlinePositions = new List<OutlinePosition>(),
                PageElementPositions = new List<PageElementPosition>()
            };

            var sw = Stopwatch.StartNew();

            _dataSource = crdo;
            _report = new PdfReport();

            _outlinePositions = new List<OutlinePosition>();
            _pageElementPositions = new List<PageElementPosition>();

            
            ComposeStandardIndicatorsSection();

            if (ShowOutlines)
            {
                if (_outlinePositions.Any())
                {
                    foreach (var parentOutlinePosition in _outlinePositions)
                    {
                        var parentOutline = _report.ParentOutline.ChildOutlines.Add(parentOutlinePosition.Name,
                            new XYDestination(parentOutlinePosition.PageNumber, 0.0f,
                                parentOutlinePosition.VerticalPosition));

                        if (parentOutlinePosition.ChildOutlinePositions == null ||
                            !parentOutlinePosition.ChildOutlinePositions.Any()) continue;

                        foreach (var childOutlinePosition in parentOutlinePosition.ChildOutlinePositions)
                        {
                            var childOutline = parentOutline.ChildOutlines.Add(childOutlinePosition.Name,
                                new XYDestination(childOutlinePosition.PageNumber, 0,
                                    childOutlinePosition.VerticalPosition));

                            if (childOutlinePosition.ChildOutlinePositions == null ||
                            !childOutlinePosition.ChildOutlinePositions.Any()) continue;

                            foreach (var subChildOutlinePosition in childOutlinePosition.ChildOutlinePositions)
                            {
                                childOutline.ChildOutlines.Add(subChildOutlinePosition.Name,
                                    new XYDestination(subChildOutlinePosition.PageNumber, 0,
                                        subChildOutlinePosition.VerticalPosition));
                            }
                        }
                    }
                }
            }


            if (_report.Pages.Any())
                result.PdfDocument = _report.Draw();

            sw.Stop();

            result.OutlinePositions = _outlinePositions;
            result.PageElementPositions = _pageElementPositions;
            result.GenerationTime = sw.Elapsed;

            return result;
        }

        private void AddThemeHeaderElement(Group pageElements, string themeName, float left, float top)
        {
            int score = 0;
            int rank = 0;
            int count = 0;
            int percentile = 0;
            float weight = 0;
            string assessment = string.Empty;
            var themeCircleColor = new RgbColor(158, 159, 163);
            bool isInReferenceUniverse = true;

            var themePerformance = GetThemePerformance(themeName);
            if (themePerformance != null)
            {
                score = themePerformance.Score;
                rank = themePerformance.Rank;
                count = themePerformance.Count;
                percentile = (int)Math.Round(themePerformance.Percentile,0,MidpointRounding.AwayFromZero);
                weight = themePerformance.Weight;
                assessment = themePerformance.Rank <= 0
                    ? string.Empty
                    : themePerformance.Assessment ?? string.Empty;
                isInReferenceUniverse = themePerformance.IsInReferenceUniverse;
            }

            var xIcon1 = left + 20f;
            var xIcon2 = left + 160f;
            var xIcon3 = left + 310f;
            var xIcon4 = left + 460f;

            var themeFormattedText = string.Format("<p><font color='FFFFFF'><b>{0}</b></font></p>", themeName);
            var weightFormattedText = "<p><b>" + themeName + "</b></p><p><b>Weight</b></p>";
            var scoreFormattedText = string.Format("<p><b>{0} Score</b></p>", themeName);
            const string relativePositionFormattedText = "<p><b>Relative</b></p><p><b>Position</b></p>";
            const string percentileFormattedText = "<p><b>Percentile</b></p>";


            pageElements.Add(new Rectangle(left, top, 530, 24, Colors.SectionColor, Colors.SectionColor));
            pageElements.Add(new FormattedTextArea(themeFormattedText, left + 5f, top + 3f, 500, 16, FontFamily.Times, 16, false));
            pageElements.Add(new Line(left, top + 30f, left + 530, top + 30, 0.5f, Colors.BarBackgroundColor));


            if (_dataSource.ReportType == ReportType.CoreReport || 
                _dataSource.ReportType == ReportType.SummaryCoreReport) return;

            pageElements.Add(new Circle(xIcon1, top + 70f, 20f, 20f, themeCircleColor, themeCircleColor, 0,
                LineStyle.Solid));
            pageElements.Add(new Label(weight.ToString("#%"), xIcon1 - 20, top + 62f, 40f, 40f, Fonts.CalibriBold,
                20, TextAlign.Center, RgbColor.White));
            pageElements.Add(new FormattedTextArea(weightFormattedText, xIcon1 + 25f, top + 60f, 100f, 25,
                Fonts.CalibriFontFamily, 10, false));

            pageElements.Add(new Circle(xIcon2, top + 70f, 20f, 20f, themeCircleColor, themeCircleColor, 0,
                LineStyle.Solid));
            pageElements.Add(new Label(score.ToString(CultureInfo.InvariantCulture), xIcon2 - 20, top + 62f, 40f,
                40f, Fonts.CalibriBold, 20, TextAlign.Center, RgbColor.White));
            pageElements.Add(new FormattedTextArea(scoreFormattedText, xIcon2 + 25f, top + 60f, 100f, 25,
                Fonts.CalibriFontFamily, 10, false));
            pageElements.Add(new Line(xIcon2 + 23f, top + 71f, xIcon2 + 110f, top + 71f, 0.5f, RgbColor.Black));
            pageElements.Add(new Label(assessment, xIcon2 + 25f, top + 73f, 100f, 10f, Fonts.CalibriLight, 9,
                TextAlign.Left, RgbColor.Black));

            var colour = RgbColor.White;
            if (!isInReferenceUniverse)
                colour = RgbColor.Red;

            pageElements.Add(new Circle(xIcon3, top + 70f, 20f, 20f, themeCircleColor, themeCircleColor, 0,
                LineStyle.Solid));
            if (rank >= 0 && CompanyHasPeers(rank, count, isInReferenceUniverse))
            {
                pageElements.Add(new Label(rank.ToString(CultureInfo.InvariantCulture), xIcon3 - 20f, top + 53f, 40f,
                    14f, Fonts.CalibriBold, 14, TextAlign.Center, colour));
                pageElements.Add(new Label("out of", xIcon3 - 20f, top + 66f, 40f, 8f, Fonts.CalibriRegular, 8,
                    TextAlign.Center, colour));
                pageElements.Add(new Label(count.ToString(CultureInfo.InvariantCulture), xIcon3 - 20f, top + 74f,
                    40f,
                    14f, Fonts.CalibriBold, 14, TextAlign.Center, colour));
            }
            else
            {
                pageElements.Add(new Label("N/A", xIcon3 - 20, top + 62f, 40f, 40f, Fonts.CalibriBold, 20,
                    TextAlign.Center, colour));
            }
            pageElements.Add(new FormattedTextArea(relativePositionFormattedText, xIcon3 + 25f, top + 60f, 100f, 25,
                Fonts.CalibriFontFamily, 10, false));

            pageElements.Add(new Circle(xIcon4, top + 70f, 20f, 20f, themeCircleColor, themeCircleColor, 0,
                LineStyle.Solid));

            if (percentile == 0 && CompanyHasPeers(rank, count, isInReferenceUniverse))
                pageElements.Add(new Label(percentile.ToString(CultureInfo.InvariantCulture), xIcon4 - 20f,
                    top + 62f, 40f, 40f, Fonts.CalibriBold, 20, TextAlign.Center, colour));
            if (percentile == 100)
                pageElements.Add(new Label(percentile.ToString(CultureInfo.InvariantCulture), xIcon4 - 25f,
                    top + 62f, 40f, 40f, Fonts.CalibriBold, 18, TextAlign.Center, colour));
            if (percentile > 0 && percentile < 100)
                pageElements.Add(new Label(percentile.ToString(CultureInfo.InvariantCulture), xIcon4 - 20f,
                    top + 62f, 40f, 40f, Fonts.CalibriBold, 20, TextAlign.Center, colour));
            if (percentile < 0 || !CompanyHasPeers(rank, count, isInReferenceUniverse))
                pageElements.Add(new Label("N/A", xIcon4 - 20f, top + 62f, 40f, 40f, Fonts.CalibriBold, 20,
                    TextAlign.Center, colour));

            pageElements.Add(new Label(BulletScoreAndAssessment.OrdinalNumberSuffix(percentile), xIcon4 - 20f,
                top + 62f, 38f, 8f, Fonts.CalibriBold, 8, TextAlign.Right, colour));
            pageElements.Add(new FormattedTextArea(percentileFormattedText, xIcon4 + 25f, top + 65f, 100f, 25,
                Fonts.CalibriFontFamily, 10, false));
        }

        private static bool CompanyHasPeers(int rank, int count, bool isInReferenceUniverse)
        {
            return !(rank==1 && count==1 && !isInReferenceUniverse);
        }

        private void AddIndicatorElements(Group pageElements, RPIndicatorExtended indicator, float left, float top)
        {
            var indicatorCircleColor = new RgbColor(46, 164, 150);
            
            pageElements.Add(new Circle(left + 25f, top + 42f, 20f, 20f, indicatorCircleColor, indicatorCircleColor,
                0, LineStyle.Solid));
            pageElements.Add(new Label(indicator.SelectedAnswer.Score.Value.ToString("N0"), left + 5, top + 34f, 40f, 40f,
                Fonts.CalibriBold, 18, TextAlign.Center, RgbColor.White));

            if (_dataSource.ReportType == ReportType.CoreReport || 
                _dataSource.ReportType == ReportType.SummaryCoreReport) return;

            if (indicator.Trend.HasValue)
            {
                if (indicator.Trend == -1)
                    pageElements.Add(new Image(ImageData.GetImage(TrendArrowDown), left + 60f, top + 67f, 0.085f)
                    {
                        Align = Align.Right,
                        VAlign = VAlign.Top
                    });
                if (indicator.Trend == 0)
                    pageElements.Add(new Image(ImageData.GetImage(TrendArrowRight), left + 60f, top + 67f, 0.085f)
                    {
                        Align = Align.Right,
                        VAlign = VAlign.Top
                    });
                if (indicator.Trend == 1)
                    pageElements.Add(new Image(ImageData.GetImage(TrendArrowUp), left + 60f, top + 67f, 0.085f)
                    {
                        Align = Align.Right,
                        VAlign = VAlign.Top
                    });
            }

            pageElements.Add(new Label("Raw Score:", left + 65f, top + 35f, 60f, 10f, Fonts.CalibriLight, 10,
                TextAlign.Left, RgbColor.Black));
            pageElements.Add(new Label("Weight:", left + 65f, top + 50f, 60f, 10f, Fonts.CalibriLight, 10,
                TextAlign.Left, RgbColor.Black));
            pageElements.Add(new Line(left + 65f, top + 65f, left + 170f, top + 65f, 0.5f, RgbColor.Black));
            pageElements.Add(new Label("Weighted score:", left + 65f, top + 70f, 70f, 10f, Fonts.CalibriLight, 10,
                TextAlign.Left, RgbColor.Black));

            pageElements.Add(new Label(indicator.SelectedAnswer.Score.Value.ToString("N0"), left + 125f, top + 35f, 50f,
                10f, Fonts.CalibriBold, 10, TextAlign.Center, RgbColor.Black));

            var weight = indicator.Weight.Value?.ToString("P2") ?? string.Empty;

            pageElements.Add(new Label(weight, left + 125f, top + 50f, 50f, 10f, Fonts.CalibriBold, 10,
                TextAlign.Center, RgbColor.Black));

            var weightedScore = indicator.WeightedScore.Value?.ToString("N2") ?? string.Empty;

            pageElements.Add(new Label(weightedScore, left + 125f, top + 70f, 50f, 10f, Fonts.CalibriBold, 10,
                TextAlign.Center, RgbColor.Black));
        }

        private void ComposeStandardIndicatorsSection()
        {
            PdfReportPage page = null;
            var left = _report.LeftMargin;
            float remainingHeight;
            float top = 0;
            const float minIndicatorHeight = 90f;
            var thinLine = true;

            var pageCount = 0;


            var outlinePosition = new OutlinePosition
            {
                Name = "Indicators",
                PageNumber = 1,
                ChildOutlinePositions = new List<OutlinePosition>()
            };

            _outlinePositions.Add(outlinePosition);

            OutlinePosition themeOutlinePosition = null;


            var theme = string.Empty;
            var indicatorCategory = string.Empty;

            if (_dataSource.StandardIndicators == null) return;
            
            var standardIndicators = _dataSource.StandardIndicators
                .Where(i => !i.Template.Number.Contains("P"))
                .OrderBy(si => si.Template.ThemeSortKey)
                .ThenBy(si => si.Template.IndicatorCategorySortKey)
                .ThenBy(si => si.Template.SortKey)
                .ToList();

            foreach (var standardIndicator in standardIndicators)
            {
                if (theme != standardIndicator.Template.ThemeName)
                {
                    page = _report.NewPage();
                    _report.Pages.Add(page);
                    pageCount++;

                    top = 0;

                    themeOutlinePosition = new OutlinePosition
                    {
                        Id = standardIndicator.Template.Id,
                        Name = standardIndicator.Template.ThemeName,
                        PageNumber = pageCount,
                        VerticalPosition = top,
                        ChildOutlinePositions = new List<OutlinePosition>()
                    };
                    outlinePosition.ChildOutlinePositions.Add(themeOutlinePosition);

                    AddThemeHeaderElement(page.Elements, standardIndicator.Template.ThemeName, left, top);

                    if (_dataSource.ReportType != ReportType.CoreReport && 
                        _dataSource.ReportType != ReportType.SummaryCoreReport)
                    {
                        top = top + 125;
                    }
                    else
                    {
                        top = top + 30;
                    }
                }

                theme = standardIndicator.Template.ThemeName;

                remainingHeight = _report.PageMaxHeight - top;

                if (indicatorCategory != standardIndicator.Template.IndicatorCategory && 
                    _dataSource.ReportType != ReportType.CoreReport && 
                    _dataSource.ReportType != ReportType.SummaryCoreReport)
                {                  
                    if (remainingHeight - 25 < minIndicatorHeight)
                    {
                        page = _report.NewPage();
                        _report.Pages.Add(page);
                        pageCount++;

                        top = 0;
                        remainingHeight = _report.PageMaxHeight - 25;
                    }

                    themeOutlinePosition.ChildOutlinePositions.Add(new OutlinePosition
                    {
                        Name = standardIndicator.Template.IndicatorCategory,
                        PageNumber = pageCount,
                        VerticalPosition = top,
                        ChildOutlinePositions = null
                    });

                    page.Elements.Add(new Rectangle(left, top, 530, 24, Colors.SectionColor, Colors.SectionColor));
                    page.Elements.Add(new Label(string.Format("{0} - {1}", standardIndicator.Template.ThemeName, standardIndicator.Template.IndicatorCategory), left + 5f, top + 3f, 500, 12, Font.TimesBold, 14));
                    top = top + 30;
                    thinLine = false;
                }


                indicatorCategory = standardIndicator.Template.IndicatorCategory;


                if (top > 700)
                {
                    page = _report.NewPage();
                    _report.Pages.Add(page);
                    pageCount++;

                    top = 0;
                    remainingHeight = _report.PageMaxHeight - 25;
                }

                if (thinLine)
                    page.Elements.Add(new Line(left, top, left + 530, top, 0.5f, RgbColor.Black));
                else
                    thinLine = true;

                string indicatorNameFormattedText = string.Format("<p><b>{0}</b></p>", standardIndicator.Template.Name);
                page.Elements.Add(new FormattedTextArea(indicatorNameFormattedText, left, top + 5, 500f, 25f, Fonts.CalibriFontFamily, 10, false));
                page.Elements.Add(new Label(standardIndicator.Number, left + 430f, top + 5f, 100f, 10f, Fonts.CalibriLight, 6, TextAlign.Right, RgbColor.Black));


                AddIndicatorElements(page.Elements, standardIndicator, left, top);

                float eventIndicatorListHeight = 0;

                if (standardIndicator.Template.IsControversyIndicator)
                {
                    var controversyIndicator = GetControversyIndicator(standardIndicator.Template.Id);

                    if (controversyIndicator != null)
                    {
                        if (controversyIndicator.AnswerCategory > 0)
                        {
                            AddCategoryElement(page.Elements, controversyIndicator.AnswerCategory, left + 190f, top + 42f, true);

                            var eventIndicators = controversyIndicator.EventIndicators.OrderBy(ei => ei.Name).ToList();

                            if (eventIndicators.Any())
                            {
                                var eiLeft = left + 235f;
                                var eiTop = top + 47f;
                                const float eiWidth = 135f;
                                const int eiFontSize = 9;

                                eventIndicators.ForEach(ei =>
                                {
                                    page.Elements.Add(
                                        new Label(ei.Name, eiLeft, eiTop, eiWidth, eiFontSize + 2f, Fonts.CalibriRegular, eiFontSize));

                                    _pageElementPositions.Add(new PageElementPosition
                                    {
                                        Id = ei.Id,
                                        Name = ei.Name,
                                        PageNumber = pageCount,
                                        HorizontalPosition = eiLeft,
                                        VerticalPosition = eiTop,
                                        Height = eiFontSize + 2f,
                                        Width = eiWidth
                                    });

                                    eiTop += 12f;
                                    eventIndicatorListHeight += 12;
                                });

                                eventIndicatorListHeight += 5;
                            }

                            if (controversyIndicator.OutlookScore.HasValue)
                            {
                                AddOutlookElement(page.Elements,
                                    controversyIndicator == null ? 0 : controversyIndicator.OutlookScore.Value, left + 395f,
                                    top + 42f, 0);
                            }
                        }
                        else
                        {
                            page.Elements.Add(new Label("No evidence of relevant controversies", left + 190f, top + 35f,
                                250f, 10f, Fonts.CalibriBold, 9, TextAlign.Left, RgbColor.Black));
                        }
                    }
                }

                float answerCategoryHeight;
                if (!standardIndicator.Template.IsControversyIndicator)
                {
                    var answerCategoryFormattedText = string.Format("<p><b>{0}</b></p>", standardIndicator.SelectedAnswer.Text);
                    var answerCategoryFormattedTextArea = new FormattedTextArea(answerCategoryFormattedText, left + 190f, top + 25f, 340f, 50f, Fonts.CalibriFontFamily, 9, false);
                    page.Elements.Add(answerCategoryFormattedTextArea);
                    answerCategoryHeight = (float)Math.Round((decimal)answerCategoryFormattedTextArea.GetRequiredHeight(), 0, MidpointRounding.AwayFromZero);
                    remainingHeight = remainingHeight - answerCategoryHeight + 5;
                }
                else
                {
                    answerCategoryHeight = eventIndicatorListHeight + 25;
                }


                var indicatorHeigh = 30 + answerCategoryHeight;
                remainingHeight = remainingHeight - (25 + answerCategoryHeight);
                top = top + 30 + answerCategoryHeight;


                var style = new FormattedTextAreaStyle(Fonts.CalibriFontFamily, 9f, false)
                {
                    Paragraph =
                    {
                        Align = TextAlign.Justify,
                        Indent = 0,
                        SpacingAfter = 0,
                        AllowOrphanLines = false
                    }
                };

                if (_dataSource.ReportType != ReportType.CoreReport &&
                    _dataSource.ReportType != ReportType.SummaryCoreReport &&
                    !standardIndicator.Template.IsControversyIndicator &&
                    !string.IsNullOrWhiteSpace(standardIndicator.Comments))
                {
                    var formattedText = HTMLConvertor.ConvertComment(standardIndicator.Comments);

                    var formattedTextArea = new FormattedTextArea(formattedText, left + 190f, top, 340, remainingHeight, style);
                    page.Elements.Add(formattedTextArea);

                    var hasOverflowText = formattedTextArea.HasOverflowText();
                    
                    var requiredHeight = (float)Math.Round((decimal)formattedTextArea.GetRequiredHeight(), 0, MidpointRounding.AwayFromZero);
                    indicatorHeigh = indicatorHeigh + requiredHeight + 5;
                    remainingHeight = remainingHeight - (requiredHeight + 5);
                    top = top + requiredHeight + 5;

                    if (hasOverflowText)
                    {
                        if (top > 700)
                        {
                            page = _report.NewPage();
                            _report.Pages.Add(page);
                            pageCount++;

                            top = 0;
                            remainingHeight = _report.PageMaxHeight - 25;
                        }

                        formattedTextArea = formattedTextArea.GetOverflowFormattedTextArea(left + 190f, top, remainingHeight);
                        if (formattedTextArea != null)
                        {
                            page.Elements.Add(formattedTextArea);

                            requiredHeight = (float)Math.Round((decimal)formattedTextArea.GetRequiredHeight(), 0, MidpointRounding.AwayFromZero);

                            indicatorHeigh = indicatorHeigh + requiredHeight + 5;
                            remainingHeight = remainingHeight - (requiredHeight + 5);
                            top = top + requiredHeight + 5;
                        }
                    }
                }

                var table = GetIndicatorDataTable(standardIndicator.DataTable, left, top);

                if (table != null)
                {
                    page.Elements.Add(table);

                    var dataTableHeight = table.Height;

                    if (dataTableHeight > 0)
                    {
                        indicatorHeigh = indicatorHeigh + dataTableHeight + 5;
                        remainingHeight = remainingHeight - (dataTableHeight + 5);
                        top = top + dataTableHeight + 5;
                    }
                }

                AddIndicatorTickboxes(standardIndicator.Tickboxes, ref page, ref pageCount, ref remainingHeight, ref indicatorHeigh, ref top);

                if (indicatorHeigh < minIndicatorHeight)
                {
                    remainingHeight = remainingHeight - (minIndicatorHeight - indicatorHeigh);
                    top = top + (minIndicatorHeight - indicatorHeigh);
                }
            }
        }

        private Table GetIndicatorDataTable(List<DataHistory> dataTable, float left, float top)
        {
            if (_dataSource.ReportType == ReportType.CoreReport || 
                _dataSource.ReportType == ReportType.SummaryCoreReport) return null;

            if (!dataTable.Any()) return null;
            
            var indicatorDataTable = dataTable.OrderBy(idt => idt.Name)
                .ThenByDescending(idt => idt.Year)
                .ToList();

            var years = indicatorDataTable.GroupBy(idt => idt.Year)
                .Select(idt => idt.Key)
                .ToList();

            const int tableHeight = 40;

            var table = new Table(left + 190f, top, 340, tableHeight, Fonts.CalibriLight, 9);
            table.Border.Width = 0f;
            table.CellSpacing = 0.0f;
            table.CellDefault.Align = TextAlign.Left;
            table.CellDefault.VAlign = VAlign.Top;
            table.CellDefault.Padding.Value = 0.0f;
            table.CellDefault.Border.Color = RgbColor.Blue;
            table.CellDefault.Border.Width = 0f;
            table.CellDefault.Border.LineStyle = LineStyle.None;
            table.Border.Color = Grayscale.Black;
            table.RepeatColumnHeaderCount = 0;
            table.RepeatRowHeaderCount = 0;
            table.Columns.Add(150);

            years.ForEach(year => table.Columns.Add(40));

            var row = table.Rows.Add(10);
            row.Cells.Add("", Fonts.CalibriLight, 9, RgbColor.Black, RgbColor.White, 1);
            foreach (var year in years)
            {
                row.Cells.Add(year.ToString(CultureInfo.InvariantCulture), Fonts.CalibriLight, 9, RgbColor.Black, RgbColor.White, 1);
            }

            var name = string.Empty;

            foreach (var item in indicatorDataTable)
            {
                if (name != item.Name)
                {
                    row = table.Rows.Add(10);
                    row.Cells.Add(item.Name, Fonts.CalibriLight, 9, RgbColor.Black, RgbColor.White, 1);
                }
                row.Cells.Add(item.Value, Fonts.CalibriLight, 9, RgbColor.Black, RgbColor.White, 1);

                name = item.Name;
            }

            return table;
        }

        private void AddIndicatorTickboxes(List<Tickbox> indicatorTickboxes,
            ref PdfReportPage page, ref int pageCount, ref float remainingHeight, ref float indicatorHeigh, ref float top)
        {
            var left = _report.LeftMargin;

 
            if (indicatorTickboxes == null || !indicatorTickboxes.Any()) return;

            float estimatedHeight = 0;

            indicatorTickboxes.ForEach(indicatorTickbox =>
            {
                var fta = new FormattedTextArea("<p>" + indicatorTickbox.Text + "</p>", 0f, 0f, 320f, 100f,
                    Fonts.CalibriFontFamily, 9, false);
                var requiredHeight =
                    (float) Math.Round((decimal) fta.GetRequiredHeight(), 0, MidpointRounding.AwayFromZero);

                requiredHeight += 3;

                estimatedHeight += requiredHeight;
            });

            if (remainingHeight - estimatedHeight <= 0)
            {
                page = _report.NewPage();
                _report.Pages.Add(page);
                pageCount++;

                top = 0;
                remainingHeight = _report.PageMaxHeight;
            }

            var table = new Table(left + 190f, top, 340, estimatedHeight, Fonts.CalibriLight, 9);
            table.Border.Width = 0f;
            table.CellSpacing = 0.0f;
            table.CellDefault.Align = TextAlign.Left;
            table.CellDefault.VAlign = VAlign.Top;
            table.CellDefault.Padding.Value = 0.0f;
            table.CellDefault.Border.Color = RgbColor.Blue;
            table.CellDefault.Border.Width = 0f;
            table.CellDefault.Border.LineStyle = LineStyle.None;
            table.Border.Color = Grayscale.Black;
            table.RepeatColumnHeaderCount = 0;
            table.RepeatRowHeaderCount = 0;
            table.Columns.Add(10);
            table.Columns.Add(330);

            foreach (var indicatorTickbox in indicatorTickboxes)
            {
                var fta = new FormattedTextArea("<p>" + indicatorTickbox.Text + "</p>", 0f, 0f, 320f, 100f,
                    Fonts.CalibriFontFamily, 9, false);
                var requiredHeight =
                    (float) Math.Round((decimal) fta.GetRequiredHeight(), 0, MidpointRounding.AwayFromZero);

                requiredHeight += 3;

                var tickboxRow = table.Rows.Add(requiredHeight);

                tickboxRow.Cells.Add(indicatorTickbox.IsChecked
                    ? new Image(ImageData.GetImage(TickboxChecked), 0, 0, 0.05f)
                    : new Image(ImageData.GetImage(TickboxUnchecked), 0, 0, 0.05f));

                tickboxRow.Cells.Add(new FormattedTextArea("<p>" + indicatorTickbox.Text + "</p>", 0f, 0f, 320f,
                    requiredHeight, Fonts.CalibriFontFamily, 9, false));

                top = top + requiredHeight;
                indicatorHeigh = indicatorHeigh + requiredHeight;
                remainingHeight = remainingHeight - requiredHeight;
            }

            page.Elements.Add(table);

            top = top + 5;
            indicatorHeigh = indicatorHeigh + 5;
            remainingHeight = remainingHeight - 5;
        }

        private void AddCategoryElement(Group pageElements, int category, float left, float top, bool hasLine)
        {
            pageElements.Add(new Circle(left + 20f, top, 20f, 20f, Colors.CtgColor[category], Colors.CtgColor[category], 0, LineStyle.Solid));
            pageElements.Add(new Label(category.ToString("0"), left, top - 16, 40f, 40f, Fonts.CalibriBold, 35, TextAlign.Center, RgbColor.White));

            if (hasLine)
            {
                string categoryFormattedText = string.Format("<p><b>Category {0} - {1}</b></p>", category, GetEventSeverity(category));
                var categoryFormattedTextArea = new FormattedTextArea(categoryFormattedText, left + 45f, top - 14f, 120f, 10f, Fonts.CalibriFontFamily, 9, false);
                pageElements.Add(categoryFormattedTextArea);

                pageElements.Add(new Line(left + 45f, top, left + 180f, top, 0.5f, RgbColor.Black));
            }
            else
            {
                pageElements.Add(new Label(string.Format("Category {0}", category), left + 50, top - 12f, 50f, 10f, Fonts.CalibriBold, 9, TextAlign.Left, RgbColor.Black));
                pageElements.Add(new Label(GetEventSeverity(category), left + 50, top + 2, 50f, 10f, Fonts.CalibriBold, 9, TextAlign.Left, RgbColor.Black));
            }
        }

        private void AddOutlookElement(Group pageElements, int outlook, float left, float top, int type)
        {
            if (type == 0 || type == 1)
            {
                if (outlook == 0)
                    pageElements.Add(new Image(ImageData.GetImage(OutlookArrowRight), left - 15f, top - 20f, 0.08f) { Align = Align.Left, VAlign = VAlign.Top });

                if (outlook == 1)
                    pageElements.Add(new Image(ImageData.GetImage(OutlookArrowUp), left - 15f, top - 20f, 0.08f) { Align = Align.Left, VAlign = VAlign.Top });

                if (outlook == -1)
                    pageElements.Add(new Image(ImageData.GetImage(OutlookArrowDown), left - 15f, top - 20f, 0.08f) { Align = Align.Left, VAlign = VAlign.Top });
            }
            else
            {
                if (outlook == 0)
                    pageElements.Add(new Image(ImageData.GetImage(OutlookArrowRight), left, top, 0.06f) { Align = Align.Left, VAlign = VAlign.Top });

                if (outlook == 1)
                    pageElements.Add(new Image(ImageData.GetImage(OutlookArrowUp), left, top, 0.06f) { Align = Align.Left, VAlign = VAlign.Top });

                if (outlook == -1)
                    pageElements.Add(new Image(ImageData.GetImage(OutlookArrowDown), left, top, 0.06f) { Align = Align.Left, VAlign = VAlign.Top });
            }

            if (type == 0)
            {
                pageElements.Add(new Label("Outlook", left + 35, top - 14f, 50f, 10f, Fonts.CalibriBold, 9, TextAlign.Left, RgbColor.Black));
                pageElements.Add(new Line(left + 35f, top, left + 135f, top, 0.5f, RgbColor.Black));
                pageElements.Add(new Label(GetOutlookAssessment(outlook), left + 35, top + 4, 50f, 10f, Fonts.CalibriRegular, 9, TextAlign.Left, RgbColor.Black));
            }

            if (type == 1)
            {
                pageElements.Add(new Label("Outlook", left + 35f, top - 10f, 50f, 10f, Fonts.CalibriBold, 9, TextAlign.Left, RgbColor.Black));
                pageElements.Add(new Label(GetOutlookAssessment(outlook), left + 35f, top + 2f, 50f, 10f, Fonts.CalibriRegular, 9, TextAlign.Left, RgbColor.Black));
            }

            if (type == 2)
            {
                pageElements.Add(new Label("Outlook", left + 40f, top + 4f, 50f, 10f, Fonts.CalibriBold, 9, TextAlign.Left, RgbColor.Black));
                pageElements.Add(new Label(GetOutlookAssessment(outlook), left + 40f, top + 16f, 50f, 10f, Fonts.CalibriRegular, 9, TextAlign.Left, RgbColor.Black));
            }
        }

        private string GetOutlookAssessment(int outlook)
        {
            switch (outlook)
            {
                case -1:
                    return "Negative";
                case 0:
                    return "Neutral";
                case 1:
                    return "Positive";
                default:
                    return string.Empty;
            }
        }

        public ThemePerformance GetThemePerformance(string themeName)
        {
            return _dataSource.ThemesPerformance == null ? null : _dataSource.ThemesPerformance.SingleOrDefault(t => t.ThemeName == themeName);
        }

        public RPIndicatorExtended GetIndicatorPerformance(Guid indicatorId)
        {
            return _dataSource.StandardIndicators.SingleOrDefault(i => i.Id == indicatorId && (int)i.SelectedAnswer.Score != -1);
        }

        public string GetIndicatorAssessment(int rawScore)
        {
            string assessment;

            if (rawScore >= 75)
                assessment = "Leader";
            else if (rawScore > 25 && rawScore < 75)
                assessment = "Average";
            else // <= 25
                assessment = "Laggard";

            return assessment;
        }

        public RPControversyIndicator GetControversyIndicator(Guid controversyIndicatorId)
        {
            return _dataSource.ControversyIndicators.SingleOrDefault(ci => ci.Template.Id == controversyIndicatorId);
        }

        public string GetEventSeverity(int category)
        {
            switch (category)
            {
                case 1:
                    return "Low";
                case 2:
                    return "Moderate";
                case 3:
                    return "Significant";
                case 4:
                    return "High";
                case 5:
                    return "Severe";
                default:
                    return string.Empty;
            }
        }


    }
}
